<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>JVM类加载子系统 | Kylin</title><meta name="keywords" content="Java,JVM"><meta name="author" content="Kylin"><meta name="copyright" content="Kylin"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="类加载子系统  类加载器子系统负责从文件系统或者网络中加载Class文件，class文件在文件开头有特定的文件标识。 ClassLoader只负责class文件的加载，至于它是否可以运行，则由Execution Engine（执行引擎）决定。 加载的类信息存放于一块称为方法区的内存空间。除了类的信息外，方法区中还会存放运行时常最池信息，可能还包括字符串字而量和数字常量(这部分常量信息是Class">
<meta property="og:type" content="article">
<meta property="og:title" content="JVM类加载子系统">
<meta property="og:url" content="https://www.codekylin.cn/31140.html">
<meta property="og:site_name" content="Kylin">
<meta property="og:description" content="类加载子系统  类加载器子系统负责从文件系统或者网络中加载Class文件，class文件在文件开头有特定的文件标识。 ClassLoader只负责class文件的加载，至于它是否可以运行，则由Execution Engine（执行引擎）决定。 加载的类信息存放于一块称为方法区的内存空间。除了类的信息外，方法区中还会存放运行时常最池信息，可能还包括字符串字而量和数字常量(这部分常量信息是Class">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://qiniu.codekylin.cn/github/img/img/wallhaven-492lkw.png">
<meta property="article:published_time" content="2020-10-03T01:57:13.000Z">
<meta property="article:modified_time" content="2022-07-12T11:42:50.029Z">
<meta property="article:author" content="Kylin">
<meta property="article:tag" content="Java">
<meta property="article:tag" content="JVM">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://qiniu.codekylin.cn/github/img/img/wallhaven-492lkw.png"><link rel="shortcut icon" href="https://qiniu.codekylin.cn/img/20200807181548.png"><link rel="canonical" href="https://www.codekylin.cn/31140"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//www.google-analytics.com" crossorigin=""/><link rel="preconnect" href="//hm.baidu.com"/><link rel="preconnect" href="//fonts.googleapis.com" crossorigin=""/><meta name="google-site-verification" content="gzeyWstt6NoTZKh7YFYNLNziL8HIZ8YH2Ug7xTDX5-Y"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?f76c34daefe747deee7c7be3ead2ba80";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script><script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-159334016-1"></script><script>window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-159334016-1');
</script><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium+Web" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"search.xml","languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: {"defaultEncoding":2,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"简"},
  noticeOutdate: {"limitDay":90,"position":"top","messagePrev":"自上次更新以来已经","messageNext":"天，文章的内容可能已过时或存在差异。"},
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: {"limitCount":50000,"languages":{"author":"作者: Kylin","link":"链接: ","source":"来源: Kylin","info":"著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。"}},
  lightbox: 'fancybox',
  Snackbar: {"chs_to_cht":"你已切换为繁体","cht_to_chs":"你已切换为简体","day_to_night":"你已切换为深色模式","night_to_day":"你已切换为浅色模式","bgLight":"#FF0000","bgDark":"#2d3035","position":"bottom-left"},
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: true,
  isanchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = { 
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2022-07-12 19:42:50'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
          const isLightMode = window.matchMedia('(prefers-color-scheme: light)').matches
          const isNotSpecified = window.matchMedia('(prefers-color-scheme: no-preference)').matches
          const hasNoSupport = !isDarkMode && !isLightMode && !isNotSpecified

          if (t === undefined) {
            if (isLightMode) activateLightMode()
            else if (isDarkMode) activateDarkMode()
            else if (isNotSpecified || hasNoSupport) {
              const now = new Date()
              const hour = now.getHours()
              const isNight = hour <= 6 || hour >= 18
              isNight ? activateDarkMode() : activateLightMode()
            }
            window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
              if (saveToLocal.get('theme') === undefined) {
                e.matches ? activateDarkMode() : activateLightMode()
              }
            })
          } else if (t === 'light') activateLightMode()
          else activateDarkMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const fontSizeVal = saveToLocal.get('global-font-size')
    if (fontSizeVal !== undefined) {
      document.documentElement.style.setProperty('--global-font-size', fontSizeVal + 'px')
    }
    })(window)</script><link rel="stylesheet" href="https://qiniu.codekylin.cn/github/img/img/custom.css"><link rel="stylesheet" href="//at.alicdn.com/t/font_1993646_z05rabxf05h.css"><link rel="stylesheet" href="https://qiniu.codekylin.cn/github/img/img/icon.css"><meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/atom.xml" title="Kylin" type="application/atom+xml">
</head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="author-avatar"><img class="avatar-img" data-lazy-src="https://qiniu.codekylin.cn/img/20200807181526.jpg" onerror="onerror=null;src='https://qiniu.codekylin.cn/github/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/archives/"><div class="headline">文章</div><div class="length-num">362</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/tags/"><div class="headline">标签</div><div class="length-num">427</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/categories/"><div class="headline">分类</div><div class="length-num">101</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fa fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fa fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fa fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fa fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fa fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fa fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://qiniu.codekylin.cn/github/img/img/wallhaven-492lkw.png')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">Kylin</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fa fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fa fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fa fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fa fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fa fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fa fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">JVM类加载子系统</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2020-10-03T01:57:13.000Z" title="发表于 2020-10-03 09:57:13">2020-10-03</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2022-07-12T11:42:50.029Z" title="更新于 2022-07-12 19:42:50">2022-07-12</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Java/">Java</a><i class="fas fa-angle-right post-meta-separator"></i><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Java/JVM/">JVM</a><i class="fas fa-angle-right post-meta-separator"></i><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Java/JVM/%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%AD%90%E7%B3%BB%E7%BB%9F/">类加载子系统</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">5.7k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>19分钟</span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201004145512.png" alt="JVM架构模型"></p>
<h2 id="类加载子系统"><a href="#类加载子系统" class="headerlink" title="类加载子系统"></a>类加载子系统</h2><p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003100251.png" alt="类加载子系统"></p>
<ul>
<li>类加载器子系统负责从文件系统或者网络中加载Class文件，class文件在文件开头有特定的文件标识。</li>
<li>ClassLoader<code>只负责</code>class文件的<code>加载</code>，至于它是否可以运行，则由<code>Execution Engine</code>（执行引擎）决定。</li>
<li>加载的类信息存放于一块称为<code>方法区</code>的内存空间。除了类的信息外，<strong>方法区中还会存放运行时常最池信息，可能还包括字符串字而量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)</strong></li>
</ul>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003100856.png" alt="image-20201003100855174"></p>
<ol>
<li>class file存在于本地硬盘上，可以理解为设计师画在纸上的模板，而最终这个模板在执行的时候是要加载到JVM当中来根据这个文件实例画出n个一模一样的实例。</li>
<li>class file加载到JVM中，被称为DNA元数据模板,放在<code>方法区</code>。</li>
<li>在.class文件-&gt; JVM -&gt;最终成为元数据模板,此过程就要一个<code>运输工具(类装载器Class Loader)</code> ,扮演一个快递员的角色。</li>
</ol>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003102714.png" alt="类的加载过程"></p>
<p><strong><mark>类的加载过程通过类加载子系统加载，分为三个过程：加载（Loading），链接（Linking），初始化（Initalization）。</mark></strong></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003103458.png" alt="类的加载过程2"></p>
<h2 id="加载-Loading"><a href="#加载-Loading" class="headerlink" title="加载-Loading"></a>加载-Loading</h2><ol>
<li>通过一个类的<code>全限定名</code>获取定义此类的<code>二进制字节流</code>（以物理磁盘为例）</li>
<li>将这个字节流所代表的静态存储结构转化为<code>方法区</code>的运行时数据结构</li>
<li>在内存中生成一个代表这个类的java. lang.<code>Class</code>对象，作为方法区这个类的<code>各种数据的访问入口</code></li>
</ol>
<p>加载. class文件的方式</p>
<ol>
<li>从本地系统中直接加载</li>
<li>通过网络获取，典型场景: web Applet</li>
<li>从zip压缩包中读取，成为日后jar、war格式的基础</li>
<li>运行时计算生成，使用最多的是:动态代理技术</li>
<li>由其他文件生成，典型场景: JSP应用</li>
<li>从专有数据库中提取. class文件,比较少见</li>
<li>从加密文件中获取，典型的防Class文件被反编译的保护措施</li>
</ol>
<p><strong><mark>生成java.lang.Class对象在这个阶段出现</mark></strong></p>
<h2 id="链接-Linking"><a href="#链接-Linking" class="headerlink" title="链接-Linking"></a>链接-Linking</h2><h3 id="验证-Verify"><a href="#验证-Verify" class="headerlink" title="验证(Verify)"></a>验证(Verify)</h3><ul>
<li>目的在于<code>确保Class文件的字节流中包含信息符合当前虚拟机要求</code>，保证<code>被加载类的正确性</code>，不会危害虚拟机自身安全。（虚拟机要求：例如字节码文件以<code>cafebabe</code>开头等）</li>
<li>主要包括<code>四种验证</code>，文件格式验证，元数据验证，字节码验证，符号引用验证。（验证出错会报VerifyError错误）</li>
</ul>
<p>查看字节码文件 （我这使用的是vim命令。%!xxd），也可以使用相关工具</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003104512.png" alt="image-20201003104510595"></p>
<h3 id="准备-Prepare"><a href="#准备-Prepare" class="headerlink" title="准备(Prepare)"></a>准备(Prepare)</h3><ul>
<li>为类变量分配内存并且设置该类变量的默认初始值。</li>
<li>这里<code>不包含用final修饰的static,</code>因为final在编译的时候就会分配了，<code>准备阶段会显式初始化;</code></li>
<li>这里不会为<code>实例变量分配初始化</code>，<code>类变量会在方法区中，而实例变量是会随着对象一起分配到Java堆中</code>。</li>
</ul>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003104819.png" alt="image-20201003104818195"></p>
<p>如图该int型变量显示赋值为1，在类加载过程中的链接Linking阶段中，该变量在准备阶段Prepare为该变量分配内存，并且设置该类变量的默认初始值<code>a = 0;</code> 在初始化（Initalization）阶段才会赋值<code>a  = 2;</code></p>
<h3 id="解析-Resolve"><a href="#解析-Resolve" class="headerlink" title="解析(Resolve)"></a>解析(Resolve)</h3><ul>
<li>将<code>常量池内</code>的符号引用转换为直接引用的过程。</li>
<li>事实上，<code>解析操作</code>往往会伴随着<code>JVM在执行完*初始化*之后再执行</code>。</li>
<li>符号引用就是一组符号来描述所引用的目标。符号引用的字面量形式明确定义在《java虚拟机规范》的class文件格式中。直接引用就是直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄。</li>
<li><code>解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等</code>。对应常量池中的CONSTANT_ Class_ info、 CONSTANT_ Fieldref_ info、 CONSTANT Methodref_ info等。</li>
</ul>
<h2 id="初始化-Initialization"><a href="#初始化-Initialization" class="headerlink" title="初始化-Initialization"></a>初始化-Initialization</h2><ul>
<li>初始化阶段就是执行<code>类构造器方法&lt; clinit &gt; ()</code>的过程。（注意：这个方法和类中定义的构造方法不一样）</li>
<li>此方法不需定义，<code>是javac编译器</code>自动收集类中的所有<code>类变量(静态变量)</code>的赋值动作和<code>静态代码块</code>中的语句（也就是static修饰的）<code>合并而来</code>。Clinit构造器会把显示初始化和构造代码块初始化合并在一起构成构造器方法，如果没有类变量（静态变量）的赋值动作或者是静态代码块语句那么就不会生成这个clinit方法了。还有一点：<code>&lt; init &gt; ()</code>这个就是默认的构造方法。</li>
<li>构造器方法中指令按语句在源文件中出现的<code>顺序执行</code>。类成员加载顺序是：父类的静态字段——&gt;父类静态代码块——&gt;子类静态字段——&gt;子类静态代码块——&gt;父类成员变量（非静态字段）——&gt;父类非静态代码块——&gt;父类(无参)构造器——&gt;子类成员变量——&gt;子类非静态代码块——&gt;子类构造器，这里要<code>注意的就是静态字段和静态代码块之间对类（静态）变量的初始化，是按照书写顺序的，并不是按照先字段初始化再代码块初始化</code>。</li>
<li>&lt; clinit &gt;() <code>不同于类的构造器</code>。(关联: 构造器是虚拟机视角下的&lt; init &gt; ())</li>
<li>若该类具有父类，JVM会保证子类的&lt; clinit &gt;()执行前，父类的&lt; clinit &gt;()已经执行完毕。</li>
<li>虚拟机必须保证一个类的&lt; clinit &gt;()方法在<code>多线程下被同步加锁</code>。</li>
</ul>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003110104.png" alt="image-20201003110102857"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassInitTest</span> </span>&#123;</span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> num = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">static</span>&#123;</span><br><span class="line">       num = <span class="number">2</span>;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        System.out.println(ClassInitTest.num);<span class="comment">//2</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>使用<code>Jclasslib</code>插件查看该类的字节码文件</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003110315.png" alt="image-20201003110313444"></p>
<p>可以看到该变量一开始赋值为1，后赋值为2。构造器方法中指令按语句在源文件中出现的<code>顺序执行</code></p>
<p>构造器方法中指令按语句在源文件中出现的<code>顺序执行</code>。类成员加载顺序是：父类的静态字段——&gt;父类静态代码块——&gt;子类静态字段——&gt;子类静态代码块——&gt;父类成员变量（非静态字段）——&gt;父类非静态代码块——&gt;父类(无参)构造器——&gt;子类成员变量——&gt;子类非静态代码块——&gt;子类构造器，这里要<code>注意的就是静态字段和静态代码块之间对类（静态）变量的初始化，是按照书写顺序的，并不是按照先字段初始化再代码块初始化</code>。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003110908.png" alt="image-20201003110906596"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassInitTest</span> </span>&#123;</span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> num = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">static</span>&#123;</span><br><span class="line">       num = <span class="number">2</span>;</span><br><span class="line">       number = <span class="number">20</span>;</span><br><span class="line">       System.out.println(num);</span><br><span class="line">       <span class="comment">//System.out.println(number);//报错：非法的前向引用。</span></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> number = <span class="number">10</span>;  <span class="comment">//linking之prepare: number = 0 --&gt; initial: 20 --&gt; 10</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        System.out.println(ClassInitTest.num);<span class="comment">//2</span></span><br><span class="line">        System.out.println(ClassInitTest.number);<span class="comment">//10</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>静态代码块中的int型变量number的值变化为，在链接-Linking阶段中的prepare准备阶段初始化值为0，再在初始-Initializationg阶段顺序执行 <code>number = 20</code>在<code>number = 10</code>。</p>
<p>linking之prepare: number = 0 –&gt; initial: 20 –&gt; 10</p>
<p>&lt; clinit &gt;() <code>不同于类的构造器</code>。(关联: 构造器是虚拟机视角下的&lt; init &gt; ())</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003111737.png" alt="image-20201003111723231"></p>
<p>当我们类中没有静态的变量和静态代码块，此时的字节码文件中Methods是没有<code>&lt;clinit&gt;</code>的。</p>
<p>类的构造器就是字节码中Methods的<code>&lt;init&gt;</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003112117.png" alt="image-20201003112115369"></p>
<p>可以看见在Methods中的<code>&lt;init&gt;</code>对a，d变量进行了赋值。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClinitTest</span> </span>&#123;</span><br><span class="line">    <span class="comment">//任何一个类声明以后，内部至少存在一个类的构造器 (Methods-init)</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> a = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> c = <span class="number">3</span>;<span class="comment">//(Methods-clinit)</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">int</span> b = <span class="number">2</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ClinitTest</span><span class="params">()</span></span>&#123;</span><br><span class="line">        a = <span class="number">10</span>;</span><br><span class="line">        <span class="keyword">int</span> d = <span class="number">20</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>若该类具有父类，JVM会保证子类的&lt; clinit &gt;()执行前，父类的&lt; clinit &gt;()已经执行完毕。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003112651.png" alt="image-20201003112642884"></p>
<p>虚拟机必须保证一个类的&lt; clinit &gt;()方法在<code>多线程下被同步加锁</code>。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003112909.png" alt="image-20201003112908380"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DeadThreadTest</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Runnable r = () -&gt; &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;开始&quot;</span>);</span><br><span class="line">            DeadThread dead = <span class="keyword">new</span> DeadThread();</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;结束&quot;</span>);</span><br><span class="line">        &#125;;</span><br><span class="line"></span><br><span class="line">        Thread t1 = <span class="keyword">new</span> Thread(r,<span class="string">&quot;线程1&quot;</span>);</span><br><span class="line">        Thread t2 = <span class="keyword">new</span> Thread(r,<span class="string">&quot;线程2&quot;</span>);</span><br><span class="line"></span><br><span class="line">        t1.start();</span><br><span class="line">        t2.start();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">DeadThread</span></span>&#123;</span><br><span class="line">    <span class="keyword">static</span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;初始化当前类&quot;</span>);</span><br><span class="line">            <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>资源类<code>DeadThread</code>中创建了一个静态代码块（保证在该类的&lt; cInit &gt;）中有一个打印语句，后进行无限循环。</p>
<p>接着主函数中两线程分别调用该资源类。查看效果当其中一个线程首先被调用执行后进实例化资源类而输出打印语句。按理来说我们是没有对其进行加锁同步操作的，所以一般情况下当一线程首先对资源类进行实例化后，可能会被另个线程个打断，从而再次输出打印语句。</p>
<p>但是我们从运行结果得知当有一个线程对该类进行实例化输出打印语句而死循环后，是没有被抢占的。也就是该过程是被加锁的。原因就是：虚拟机必须保证一个类的&lt; clinit &gt;()方法在<code>多线程下被同步加锁</code>。也就是static代码块只被加载一次。</p>
<h2 id="类加载器分类"><a href="#类加载器分类" class="headerlink" title="类加载器分类"></a>类加载器分类</h2><ul>
<li>JVM支持两种类型的类加载器，分别为<code>引导类加载器</code>( Bootstrap ClassLoader它不是java语言编写）和<code>自定义类加载器</code>(User- Defined ClassLoader)</li>
<li>从概念上来讲，自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器，但是Java虚拟机规范却没有这么定义，而是<code>将所有派生于抽象类ClassLoader的类加载器都划分为自定义类加载器</code></li>
<li>无论类加载器的类型如何划分，<code>在程序中我们最常见的类加载器始终只有3个</code>，如下所示:</li>
</ul>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003121022.png" alt="类加载器"></p>
<p>这里的四者之间的关系是包含关系。不是上层下层，也不是子父类的继承关系。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003121504.png" alt="image-20201003121501346"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003121602.png" alt="image-20201003121601450"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003121623.png" alt="image-20201003121622538"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassLoaderTest</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//获取系统类加载器</span></span><br><span class="line">        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();</span><br><span class="line">        System.out.println(systemClassLoader);<span class="comment">//sun.misc.Launcher$AppClassLoader@18b4aac2</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">//获取其上层：扩展类加载器</span></span><br><span class="line">        ClassLoader extClassLoader = systemClassLoader.getParent();</span><br><span class="line">        System.out.println(extClassLoader);<span class="comment">//sun.misc.Launcher$ExtClassLoader@1540e19d</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">//获取其上层：获取不到引导类加载器</span></span><br><span class="line">        ClassLoader bootstrapClassLoader = extClassLoader.getParent();</span><br><span class="line">        System.out.println(bootstrapClassLoader);<span class="comment">//null</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">//对于用户自定义类来说：默认使用系统类加载器进行加载</span></span><br><span class="line">        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();</span><br><span class="line">        System.out.println(classLoader);<span class="comment">//sun.misc.Launcher$AppClassLoader@18b4aac2</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">//String类使用引导类加载器进行加载的。---&gt; Java的核心类库都是使用引导类加载器进行加载的。</span></span><br><span class="line">        ClassLoader classLoader1 = String.class.getClassLoader();</span><br><span class="line">        System.out.println(classLoader1);<span class="comment">//null</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Java的核心类库都是使用引导类加载器进行加载的。</p>
<h2 id="启动类加载器"><a href="#启动类加载器" class="headerlink" title="启动类加载器"></a>启动类加载器</h2><p>启动类加载器，又称引导类加载器，Bootstrap Clas sLoader。</p>
<ul>
<li>这个类加载使用<code>C/C++语言实现</code>的，并不继承java体系机构的java. lang. ClassLoader,<code>没有父加载器</code>，嵌自在JVM内部。这个类加载器我们是获取不到的</li>
<li>它<code>用来加载Java的核心库</code>(JAVA HOME/j re/lib/rt. jar、resources. j ar或sun. boot . class . path路径下的内容) ,用于提供JVM自身需要的类</li>
<li><code>加载扩展类和应用程序类加载器</code>，并指定为他们的父类加载器。</li>
<li>出于安全考虑，<code>Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类</code></li>
</ul>
<p>通过代码查看BootstrapClassLoader能够加载的api的路径。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003143610.png" alt="image-20201003143609675"></p>
<p>我们从<code>jre/lib/jsse.jar</code>包下查看，找到<code>Provider</code>类，获取它的类加载器。来验证。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003143810.png" alt="image-20201003143809486"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003143912.png" alt="image-20201003143911231"></p>
<p>类加载器为null，也即就是启动类加载器。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassLoaderTest1</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;**********启动类加载器**************&quot;</span>);</span><br><span class="line">        <span class="comment">//获取BootstrapClassLoader能够加载的api的路径</span></span><br><span class="line">        URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();</span><br><span class="line">        <span class="keyword">for</span> (URL element : urLs) &#123;</span><br><span class="line">            System.out.println(element.toExternalForm());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//从上面的路径中随意选择一个类,来看看他的类加载器是什么:引导类加载器</span></span><br><span class="line">        ClassLoader classLoader = Provider.class.getClassLoader();<span class="comment">//jsse.jar</span></span><br><span class="line">        System.out.println(classLoader);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="扩展类加载器"><a href="#扩展类加载器" class="headerlink" title="扩展类加载器"></a>扩展类加载器</h2><ul>
<li><code>Java语言编写</code>，由sun . misc . LauncherSExtClassLoader实现。</li>
<li><code>派生于ClassLoader类</code></li>
<li><code>父类加载器为启动类加载器</code></li>
<li>从<code>java. ext.dirs系统属性所指定的目录中加载类库</code>，或从JDK的安装目录的<code>jre/lib/ext子目录</code>(扩展目录)下加载类库。<code>如果用户创建的JAR放在此目录下，也会自动由扩展类加载器加载。</code></li>
</ul>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003144219.png" alt="image-20201003144217025"></p>
<p>我们找到<code>jre/lib/ext/sunec.jar</code>下的<code>CurveDB</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003144525.png" alt="image-20201003144524287"></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003144614.png" alt="image-20201003144612902"></p>
<p>使用的是<code>sun.misc.Launcher$ExtClassLoader@7229724f</code>扩展类加载器</p>
<h2 id="应用程序类加载器"><a href="#应用程序类加载器" class="headerlink" title="应用程序类加载器"></a>应用程序类加载器</h2><p>系统类加载器，AppClassLoader</p>
<ul>
<li>jaya语言编写，由sun . mi sc . LauncherSAppClassLoader实现</li>
<li>派生于ClassLoader类</li>
<li>父类加载器为扩展类加载器</li>
<li>它负责加载环境变量classpath或系统属性java.class.path 指定路径下的类库</li>
<li><code>该类加载是程序中默认的类加载器</code>，一般来说，Java应用的类 都是由它来完成加载</li>
<li>通过ClassLoader#getSystemClassLoader ()方法可以获取到该类加载器</li>
</ul>
<h2 id="用户自定义类加载器"><a href="#用户自定义类加载器" class="headerlink" title="用户自定义类加载器"></a>用户自定义类加载器</h2><p>在Java的日 常应用程序开发中，类的加载几乎是由上述3种类加载器相互配合执行的，在必要时，我们还可以自定义类加载器，来定制类的加载方式。</p>
<ul>
<li>为什么要自定义类加载器?<br>隔离加载类、修改类加载的方式、扩展加载源、防止源码泄漏</li>
</ul>
<h3 id="实现步骤"><a href="#实现步骤" class="headerlink" title="实现步骤"></a>实现步骤</h3><ol>
<li>开发人员可以通过<code>继承抽象类java. lang. ClassLoader类的方式</code>， 实现自己的类加载器，以满足一些特殊的需求</li>
<li>在JDK1.2之前， 在自定义类加载器时，总会去继承ClassLoader类并重写loadClass()方法，从而实现自定义的类加载类，但是在<code>JDK1.2之后</code>已不再建议用户去覆盖loadClass()方法，而是<code>建议把自定义的类加载逻辑写在findClass()方法中</code></li>
<li>在编写自定义类加载器时，如果没有太过于复杂的需求，<code>可以直接继承URLClassLoader类</code>，这样就可以<code>避免自己去编写findClass()方法</code>及<code>其获取字节码流的方式</code>，使自定义类加载器编写更加简洁。</li>
</ol>
<h2 id="ClassLoader类"><a href="#ClassLoader类" class="headerlink" title="ClassLoader类"></a>ClassLoader类</h2><p>ClassLoader类，它是一个抽象类，其后所有的类加载器都继承自ClassLoader（不包括启动类加载器）</p>
<table>
<thead>
<tr>
<th>方法名称</th>
<th>描述</th>
</tr>
</thead>
<tbody><tr>
<td>getParent()</td>
<td>返回该类加载器的超类加载器</td>
</tr>
<tr>
<td>loadClass(String name)</td>
<td>加载名称为name的类，返回结果为java.lang.Class类的实例</td>
</tr>
<tr>
<td>findClass(String name)</td>
<td>查找名称为name的类，返回结果为java.lang.Class类的实例</td>
</tr>
<tr>
<td>findLoadedClass(String name)</td>
<td>查找名称为name的已经被加载过的类，返回结果为java.lang.Class类的实例</td>
</tr>
<tr>
<td>defineClass(String name, byte[] b, int offing len)</td>
<td>把字节数组b中的内容转换为一个Java类，返回结果为java.lang.Class类的实例</td>
</tr>
<tr>
<td>resolveClass(Class&lt;?&gt; c)</td>
<td>连接指定的一个Java类</td>
</tr>
</tbody></table>
<h3 id="获取ClassLoader的途径"><a href="#获取ClassLoader的途径" class="headerlink" title="获取ClassLoader的途径"></a>获取ClassLoader的途径</h3><p>方式一：获取当前类的ClassLoader <code>clazz.getClassLoader()</code></p>
<p>方式二：获取当前线程上下文的ClassLoader<code>Thread.currentThread().getContextClassLoader()</code></p>
<p>方式三：获取系统的ClassLoader <code>ClassLoader.getSystemClassLoader()</code></p>
<p>方式四：获取调用者的ClassLoader<code>DriverMannger.getCallerClassLoader()</code></p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003150222.png" alt="image-20201003150220594"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ClassLoaderTest2</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//方式一：获取当前类的ClassLoader</span></span><br><span class="line">            ClassLoader classLoader = Class.forName(<span class="string">&quot;java.lang.String&quot;</span>).getClassLoader();</span><br><span class="line">            System.out.println(classLoader);</span><br><span class="line">            <span class="comment">//方式二：获取当前线程上下文的</span></span><br><span class="line">            ClassLoader classLoader1 = Thread.currentThread().getContextClassLoader();</span><br><span class="line">            System.out.println(classLoader1);</span><br><span class="line"></span><br><span class="line">            <span class="comment">//方式三：获取系统的ClassLoader</span></span><br><span class="line">            ClassLoader classLoader2 = ClassLoader.getSystemClassLoader().getParent();</span><br><span class="line">            System.out.println(classLoader2);</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">catch</span> (ClassNotFoundException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="双亲委派机制"><a href="#双亲委派机制" class="headerlink" title="双亲委派机制"></a>双亲委派机制</h2><p>Java虚拟机对class文件采用的是<code>按需加载的方式</code>，也就是说当需要使用该类时才会将它的class文件<code>加载</code>到内存生成class对象。而且加载某个类的class文件时，Java虚拟机采用的是<code>双亲委派模式</code>，即把<code>请求交由父类处理，它是一“种任务委派模式</code>。</p>
<h3 id="工作原理"><a href="#工作原理" class="headerlink" title="工作原理"></a>工作原理</h3><ol>
<li>如果一个类加载器收到了类加载请求，它并不会自己先去加载，而是把这个请求委托给父类的加载器去执行;|</li>
<li>如果父类加载器还存在其父类加)载器，则进一步向上委托，依次递归,请求最终将到达项层的启动类加载器;</li>
<li>如果父类加载器可以完成类加载;任务，就成功返回，倘若父类加载器无法完成此加载任务，子加载器才会尝试自已去加载，这就是双亲委派模式。</li>
</ol>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003151214.png" alt="双亲委派模型"></p>
<p>案例，首先我们自己创建一个<code>java.lang</code>包，在这个包下创建一个<code>String</code>类。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003151352.png" alt="image-20201003151351227"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> java.lang;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">String</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;我是自定义的String类的静态代码块！&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//错误: 在类 java.lang.String 中找不到 main 方法</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;Hello String!&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>接着我们在别的包下创建一个<code>StringTest</code>测试类。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003151525.png" alt="image-20201003151524145"></p>
<p>实例化一个<code>String</code>对象，此时是调用的是Java的核心包下的String还是我们自定的String呢？通过运行可以查看，调用的还是Java核心包下的String，该类加载器为启动类加载器，无法获取。</p>
<p>具体过程是首先由系统类加载器<code>Application ClassLoader</code>向上委托，扩展类加载器<code>Extension ClassLoader</code>无法加载，向上委托到启动引导类加载器<code>Bootstrap ClassLoader</code>可以完成对String类的加载，成功返回。</p>
<p>而我们自己的StringTest类则是一路向上委托无法处理，最后由系统类加载器<code>Application ClassLoader</code>加载。</p>
<p>我们运行一下我们创建的String类</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003152141.png" alt="image-20201003152140515"></p>
<p>发现报<code>错误: 在类 java.lang.String 中找不到 main 方法</code>这是因为使用了<code>Bootstarp ClassLoader</code>加载了Java核心包下的String类，该类中没有main方法。</p>
<p>案例二</p>
<p>在Java应用中存在着很多服务提供者接口（Service Provider Interface，SPI），这些接口允许第三方为它们提供实现，如常见的 SPI 有 JDBC、JNDI等，这些 SPI 的接口属于 Java 核心库，一般存在rt.jar包中，由Bootstrap类加载器加载。而Bootstrap类加载器无法直接加载SPI的实现类，同时由于双亲委派模式的存在，Bootstrap类加载器也无法反向委托AppClassLoader加载器SPI的实现类。在这种情况下，我们就需要一种特殊的类加载器来加载第三方的类库，而<code>线程上下文类加载器</code>（<code>双亲委派模型的破坏者</code>）就是很好的选择。<br>从图可知rt.jar核心包是有Bootstrap类加载器加载的，其内包含SPI核心接口类，由于SPI中的类经常需要调用外部实现类的方法，而jdbc.jar包含外部实现类(jdbc.jar存在于classpath路径)无法通过Bootstrap类加载器加载，因此只能委派线程上下文类加载器把jdbc.jar中的实现类加载到内存以便SPI相关类使用。显然这种线程上下文类加载器的加载方式破坏了“双亲委派模型”，它在执行过程中抛弃双亲委派加载链模式，使程序可以逆向使用类加载器，当然这也使得Java类加载器变得更加灵活。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003154300.png" alt="双亲委派案例"></p>
<h3 id="优势"><a href="#优势" class="headerlink" title="优势"></a>优势</h3><ul>
<li>避免类的重复加载</li>
<li>保护程序安全，防止核心API被随意篡改（例如：自定义类: java. lang . String， 自定义类: java. lang . String1111</li>
</ul>
<p>这种方式防止了（有意或无意的）攻击，例如：建了一个java.lang包并自定义一个String类。有了这种双亲委派机制，在加载String类时仍然会加载由jdk提供的String类，不会进行覆盖。如果这个包下创建String1111类那么会抛出<code>java.lang.SecurtyException</code>异常，不安全的包名。</p>
<p>自定义创建<code>java.lang</code>KylinStart类。</p>
<p><img src= "https://gitee.com/kylincw/images/raw/master/loading.gif" data-lazy-src="https://qiniu.codekylin.cn/img/20201003152731.png" alt="image-20201003152730307"></p>
<p>运行产生异常<code>Exception in thread &quot;main&quot; java.lang.SecurityException: Prohibited package name: java.lang</code></p>
<h3 id="沙箱安全机制"><a href="#沙箱安全机制" class="headerlink" title="沙箱安全机制"></a>沙箱安全机制</h3><p>自定义String类，但是在加载自定义String类的时候会率先使用引导类加载器加载，而引导类加载器在加载的过程中会先加载jdk自带的文件(rt. jar包中java\lang\String . class)，报错信息说没有main方法，就是因为加载的是rt. jar包中的String类。<code>这样可以保证对java核心源代码的保护，这就是沙箱安全机制。</code></p>
<h2 id="在JVM中表示两个class对象是否为同一个类存在两个必要条件"><a href="#在JVM中表示两个class对象是否为同一个类存在两个必要条件" class="headerlink" title="在JVM中表示两个class对象是否为同一个类存在两个必要条件"></a>在JVM中表示两个class对象是否为同一个类存在两个必要条件</h2><ul>
<li>类的完整类名必须一致，包括包名。</li>
<li>加载这个类的ClassLoader (指ClassLoader实例对象)必须相同。<br>换句话说，在JVM中，即使这两个类对象(class对象)来源同一个Class文件，被同一个虚拟机所加载，但<code>只要加载它们的ClassLoader实例对象不同</code>，那么这两个类对象也是<code>不相等</code>的。</li>
</ul>
<h2 id="对类加载器的引用"><a href="#对类加载器的引用" class="headerlink" title="对类加载器的引用"></a>对类加载器的引用</h2><p>JVM必须知道一个类型是由启动加载器加载的还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的，那么JVM会<code>将这个类加载器的一一个引用作为类型信息的一部分保存在方法区中。</code>当解析一个类型到另一个类型的引用的时候，<code>JVM需要保证这两个类型的类加载器是相同</code>的。</p>
<h2 id="类的主动使用和被动使用"><a href="#类的主动使用和被动使用" class="headerlink" title="类的主动使用和被动使用"></a>类的主动使用和被动使用</h2><p>Java程序对类的使用方式分为:主动使用和被动使用。区别在于会不会导致类的初始化。</p>
<p>主动使用，又分为七种情况:</p>
<ol>
<li>创建类的实例</li>
<li>访问某个类或接口的静态变量，或者对该静态变量赋值</li>
<li>调用类的静态方法</li>
<li>反射(比如: Class. forName (“com. kylin. Test”) )</li>
<li>.初始化一个类的子类</li>
<li>Java虛拟机启动时被标明为启动类的类</li>
<li>JDK 7开始提供的动态语言支持: java. lang. invoke . MethodHandle实例的解析结果REF_ getStatic、 REF_ putStatic、REF_ invokeStatic句柄对应的类没有初始化，则初始化。</li>
</ol>
<p>除了以上七种情况，其他使用Java类的方式都被看作是对类的被动使用，<code>都不会导致类的初始化</code>。</p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="mailto:undefined">Kylin</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://www.codekylin.cn/31140.html">https://www.codekylin.cn/31140.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://www.codekylin.cn" target="_blank">Kylin</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/Java/">Java</a><a class="post-meta__tags" href="/tags/JVM/">JVM</a></div><div class="post_share"><div class="social-share" data-image="https://qiniu.codekylin.cn/github/img/img/wallhaven-492lkw.png" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/social-share.js/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/social-share.js/dist/js/social-share.min.js" defer></script></div></div><div class="post-reward"><div class="reward-button button--animated"><i class="fas fa-qrcode"></i> 打赏</div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="https://qiniu.codekylin.cn/img/20200807181442.jpg" target="_blank"><img class="post-qr-code-img" data-lazy-src="https://qiniu.codekylin.cn/img/20200807181442.jpg" alt="微信"/></a><div class="post-qr-code-desc">微信</div></li><li class="reward-item"><a href="https://qiniu.codekylin.cn/img/20200807181505.jpg" target="_blank"><img class="post-qr-code-img" data-lazy-src="https://qiniu.codekylin.cn/img/20200807181505.jpg" alt="支付寶"/></a><div class="post-qr-code-desc">支付寶</div></li></ul></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/30031.html"><img class="prev-cover" data-lazy-src="https://qiniu.codekylin.cn/github/img/img/wallhaven-48wo32.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Java反射机制</div></div></a></div><div class="next-post pull-right"><a href="/62861.html"><img class="next-cover" data-lazy-src="https://qiniu.codekylin.cn/github/img/img/deepin-2.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">Java虚拟机JVM</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span> 相关推荐</span></div><div class="relatedPosts-list"><div><a href="/57124.html" title="JVM本地方法接口"><img class="cover" data-lazy-src="https://qiniu.codekylin.cn/github/img/img/wallhaven-nzj88g.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-06</div><div class="title">JVM本地方法接口</div></div></a></div><div><a href="/49112.html" title="JVM本地方法栈"><img class="cover" data-lazy-src="https://qiniu.codekylin.cn/github/images/20200718200057.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-06</div><div class="title">JVM本地方法栈</div></div></a></div><div><a href="/31722.html" title="JVM程序计数器"><img class="cover" data-lazy-src="https://qiniu.codekylin.cn/github/img/img/deepin-4.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-05</div><div class="title">JVM程序计数器</div></div></a></div><div><a href="/14679.html" title="JVM运行时数据区概述"><img class="cover" data-lazy-src="https://qiniu.codekylin.cn/github/img/img/wallhaven-dgzqkl.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-05</div><div class="title">JVM运行时数据区概述</div></div></a></div><div><a href="/19828.html" title="JVM逃逸分析"><img class="cover" data-lazy-src="https://qiniu.codekylin.cn/github/img/img20200824151925.jpg" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-13</div><div class="title">JVM逃逸分析</div></div></a></div><div><a href="/62861.html" title="Java虚拟机JVM"><img class="cover" data-lazy-src="https://qiniu.codekylin.cn/github/img/img/deepin-2.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2020-10-02</div><div class="title">Java虚拟机JVM</div></div></a></div></div></div><hr/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div class="vcomment" id="vcomment"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="card-info-avatar is-center"><img class="avatar-img" data-lazy-src="https://qiniu.codekylin.cn/img/20200807181526.jpg" onerror="this.onerror=null;this.src='https://qiniu.codekylin.cn/github/img/friend_404.gif'" alt="avatar"/><div class="author-info__name">Kylin</div><div class="author-info__description">学习不易，努力努力~</div></div><div class="card-info-data"><div class="card-info-data-item is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">362</div></a></div><div class="card-info-data-item is-center"><a href="/tags/"><div class="headline">标签</div><div class="length-num">427</div></a></div><div class="card-info-data-item is-center"><a href="/categories/"><div class="headline">分类</div><div class="length-num">101</div></a></div></div><a class="button--animated" id="card-info-btn"><i class="fas fa-bookmark"></i><span>加入书签</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/kylincw" target="_blank" title="Github"><i class="iconfont icon-github"></i></a><a class="social-icon" href="tencent://message/?Menu=yes&amp;uin=171346168&amp;Service=300&amp;sigT=45a1e5847943b64c6ff3990f8a9e644d2b31356cb0b4ac6b24663a3c8dd0f8aa12a595b1714f9d45" target="_blank" title="qq"><i class="iconfont icon-qq"></i></a><a class="social-icon" href="https://space.bilibili.com/53836035" target="_blank" title="BiliBili"><i class="iconfont icon-bilibili-line"></i></a><a class="social-icon" href="mailto:zhang171346168@qq.com" target="_blank" title="Email"><i class="iconfont icon-email1"></i></a><a class="social-icon" href="/atom.xml" target="_blank" title="RSS"><i class="iconfont icon-rss"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>公告</span></div><div class="announcement_content">学习不易，努力努力！</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%AD%90%E7%B3%BB%E7%BB%9F"><span class="toc-number">1.</span> <span class="toc-text">类加载子系统</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8A%A0%E8%BD%BD-Loading"><span class="toc-number">2.</span> <span class="toc-text">加载-Loading</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%93%BE%E6%8E%A5-Linking"><span class="toc-number">3.</span> <span class="toc-text">链接-Linking</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%AA%8C%E8%AF%81-Verify"><span class="toc-number">3.1.</span> <span class="toc-text">验证(Verify)</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%87%86%E5%A4%87-Prepare"><span class="toc-number">3.2.</span> <span class="toc-text">准备(Prepare)</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%A7%A3%E6%9E%90-Resolve"><span class="toc-number">3.3.</span> <span class="toc-text">解析(Resolve)</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96-Initialization"><span class="toc-number">4.</span> <span class="toc-text">初始化-Initialization</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8%E5%88%86%E7%B1%BB"><span class="toc-number">5.</span> <span class="toc-text">类加载器分类</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%90%AF%E5%8A%A8%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8"><span class="toc-number">6.</span> <span class="toc-text">启动类加载器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%89%A9%E5%B1%95%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8"><span class="toc-number">7.</span> <span class="toc-text">扩展类加载器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8"><span class="toc-number">8.</span> <span class="toc-text">应用程序类加载器</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%94%A8%E6%88%B7%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8"><span class="toc-number">9.</span> <span class="toc-text">用户自定义类加载器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AE%9E%E7%8E%B0%E6%AD%A5%E9%AA%A4"><span class="toc-number">9.1.</span> <span class="toc-text">实现步骤</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ClassLoader%E7%B1%BB"><span class="toc-number">10.</span> <span class="toc-text">ClassLoader类</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%8E%B7%E5%8F%96ClassLoader%E7%9A%84%E9%80%94%E5%BE%84"><span class="toc-number">10.1.</span> <span class="toc-text">获取ClassLoader的途径</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8F%8C%E4%BA%B2%E5%A7%94%E6%B4%BE%E6%9C%BA%E5%88%B6"><span class="toc-number">11.</span> <span class="toc-text">双亲委派机制</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86"><span class="toc-number">11.1.</span> <span class="toc-text">工作原理</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BC%98%E5%8A%BF"><span class="toc-number">11.2.</span> <span class="toc-text">优势</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B2%99%E7%AE%B1%E5%AE%89%E5%85%A8%E6%9C%BA%E5%88%B6"><span class="toc-number">11.3.</span> <span class="toc-text">沙箱安全机制</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%9C%A8JVM%E4%B8%AD%E8%A1%A8%E7%A4%BA%E4%B8%A4%E4%B8%AAclass%E5%AF%B9%E8%B1%A1%E6%98%AF%E5%90%A6%E4%B8%BA%E5%90%8C%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%AD%98%E5%9C%A8%E4%B8%A4%E4%B8%AA%E5%BF%85%E8%A6%81%E6%9D%A1%E4%BB%B6"><span class="toc-number">12.</span> <span class="toc-text">在JVM中表示两个class对象是否为同一个类存在两个必要条件</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%AF%B9%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8%E7%9A%84%E5%BC%95%E7%94%A8"><span class="toc-number">13.</span> <span class="toc-text">对类加载器的引用</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%B1%BB%E7%9A%84%E4%B8%BB%E5%8A%A8%E4%BD%BF%E7%94%A8%E5%92%8C%E8%A2%AB%E5%8A%A8%E4%BD%BF%E7%94%A8"><span class="toc-number">14.</span> <span class="toc-text">类的主动使用和被动使用</span></a></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/56352.html" title="be动词"><img data-lazy-src="https://qiniu.codekylin.cn/github/img/img/博客封面10.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="be动词"/></a><div class="content"><a class="title" href="/56352.html" title="be动词">be动词</a><time datetime="2022-07-12T11:47:29.800Z" title="更新于 2022-07-12 19:47:29">2022-07-12</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/36436.html" title="JVM堆内存"><img data-lazy-src="https://qiniu.codekylin.cn/img/20200418115059.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="JVM堆内存"/></a><div class="content"><a class="title" href="/36436.html" title="JVM堆内存">JVM堆内存</a><time datetime="2022-07-12T11:47:29.800Z" title="更新于 2022-07-12 19:47:29">2022-07-12</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/44292.html" title="Java多线程详解"><img data-lazy-src="https://qiniu.codekylin.cn/github/img/img/wallhaven-eorjzk.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Java多线程详解"/></a><div class="content"><a class="title" href="/44292.html" title="Java多线程详解">Java多线程详解</a><time datetime="2022-07-12T11:47:29.800Z" title="更新于 2022-07-12 19:47:29">2022-07-12</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/40200.html" title="谷粒商城记录"><img data-lazy-src="https://qiniu.codekylin.cn/github/img/img/wallhaven-6qvvrx.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="谷粒商城记录"/></a><div class="content"><a class="title" href="/40200.html" title="谷粒商城记录">谷粒商城记录</a><time datetime="2022-07-12T11:47:29.800Z" title="更新于 2022-07-12 19:47:29">2022-07-12</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/27082.html" title="Spring学习-3"><img data-lazy-src="https://qiniu.codekylin.cn/github/img/img/wallhaven-4x28xo.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Spring学习-3"/></a><div class="content"><a class="title" href="/27082.html" title="Spring学习-3">Spring学习-3</a><time datetime="2022-07-12T11:47:29.799Z" title="更新于 2022-07-12 19:47:29">2022-07-12</time></div></div></div></div></div></div></main><footer id="footer" style="background-image: url('https://qiniu.codekylin.cn/github/img/img/wallhaven-492lkw.png')"><div id="footer-wrap"><div class="copyright">&copy;2019 - 2022 By Kylin</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text"><a target="_blank" rel="noopener" href="https://beian.miit.gov.cn/"><img class="icp-icon" src="https://img.alicdn.com/tfs/TB1..50QpXXXXX7XpXXXXXXXXXX-40-40.png"><span>湘ICP备2022005420号-1</span></a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="font-plus" type="button" title="放大字体"><i class="fas fa-plus"></i></button><button id="font-minus" type="button" title="缩小字体"><i class="fas fa-minus"></i></button><button id="translateLink" type="button" title="简繁转换">繁</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><a id="to_comment" href="#post-comment" title="直达评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><div class="search-dialog__title" id="local-search-title">本地搜索</div><div id="local-input-panel"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div></div><hr/><div id="local-search-results"></div><span class="search-close-button"><i class="fas fa-times"></i></span></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/tw_cn.js"></script><script src="https://cdn.jsdelivr.net/npm/instant.page/instantpage.min.js" type="module"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><script src="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.js"></script><script src="/js/search/local-search.js"></script><div class="js-pjax"><script>function loadValine () {
  function initValine () {
    const valine = new Valine(Object.assign({
      el: '#vcomment',
      appId: 'ClIyIUhj1ue2rcRTsApYCR50-gzGzoHsz',
      appKey: 'ATug9IScYQBHILhKWEqBHYxM',
      placeholder: '昵称填入QQ号能获取到QQ头像哦~请输入正确的邮箱地址，你将会快速收到我的回复并且通过邮件通知你！~',
      avatar: 'robohash',
      meta: 'nick,mail,link'.split(','),
      pageSize: '10',
      lang: 'zh-cn',
      recordIP: false,
      serverURLs: 'https://cliyiuhj.lc-cn-n1-shared.com',
      emojiCDN: '',
      emojiMaps: "",
      enableQQ: true,
      path: window.location.pathname,
      requiredFields: ["nick,mail"],
      visitor: false
    }, null))
  }

  if (typeof Valine === 'function') initValine() 
  else getScript('https://cdn.jsdelivr.net/npm/valine/dist/Valine.min.js').then(initValine)
}

if ('Valine' === 'Valine' || !true) {
  if (true) btf.loadComment(document.getElementById('vcomment'),loadValine)
  else setTimeout(loadValine, 0)
} else {
  function loadOtherComment () {
    loadValine()
  }
}</script></div><script defer="defer" id="ribbon" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-ribbon.min.js" size="150" alpha="0.6" zIndex="-1" mobile="false" data-click="true"></script><script defer="defer" id="fluttering_ribbon" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-fluttering-ribbon.min.js"></script></div></body></html>